/*
 * MIT License
 *
 * Copyright (c) 2023 北京凯特伟业科技有限公司
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
package com.je.common.base.office.service;

import cn.hutool.core.io.IoUtil;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.je.common.base.DynaBean;
import com.je.common.base.document.InternalFileBO;
import com.je.common.base.office.util.OfficeUtil;
import com.je.common.base.office.vo.JeOfficeVo;
import com.je.common.base.office.vo.JeWordTableVo;
import com.je.common.base.office.vo.JeWordVo;
import com.je.common.base.office.vo.OfficeDataVo;
import com.je.common.base.service.rpc.DocumentInternalRpcService;
import com.je.common.base.util.ArrayUtils;
import com.je.common.base.util.AsposeUtils;
import com.je.common.base.util.DateUtils;
import com.je.common.base.util.StringUtil;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.util.Units;
import org.apache.poi.xddf.usermodel.chart.*;
import org.apache.poi.xwpf.usermodel.*;
import org.apache.xmlbeans.XmlException;
import org.openxmlformats.schemas.drawingml.x2006.chart.CTDLbls;
import org.openxmlformats.schemas.drawingml.x2006.chart.CTRadarChart;
import org.openxmlformats.schemas.drawingml.x2006.chart.CTRadarSer;
import org.openxmlformats.schemas.drawingml.x2006.chart.CTValAx;
import org.openxmlformats.schemas.drawingml.x2006.main.CTLineProperties;
import org.openxmlformats.schemas.drawingml.x2006.main.STPresetLineDashVal;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.io.*;
import java.util.*;

@Component("jeWordService")
public class JeWordServiceImpl implements JeWordService {
    @Autowired
    private DocumentInternalRpcService documentInternalRpcService;
    @Autowired
    private JeOfficeService jeOfficeService;
    @Override
    public void doExecOffice(JeOfficeVo jeOfficeVo, JSONObject returnObj) {
        String fileKey=OfficeUtil.getFileKey(jeOfficeVo.getFile());
        if (StringUtil.isEmpty(fileKey)) {
            returnObj.put("success", false);
            returnObj.put("obj", "模版文件未上传");
        }
        JeWordVo jeWordVo = new JeWordVo();
//        FileBO fileIo = documentBusService.readFile(fileKey);
        InternalFileBO fileBO=documentInternalRpcService.selectFileByKey(fileKey);
        File file=documentInternalRpcService.readFile(fileKey);
        FileInputStream fileIo=null;
        if (!file.exists()) {
            returnObj.put("success", false);
            returnObj.put("obj", jeOfficeVo.getCode()+"模版文件不存在!");
            return;
        }
        jeOfficeVo.setFileContextType(fileBO.getContentType());
        try {
            fileIo=new FileInputStream(file);
            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
            XWPFDocument doc = new XWPFDocument(fileIo);
            jeWordVo.setDoc(doc);
            jeOfficeVo.setJeWordVo(jeWordVo);
            //执行事件
            //执行事件
            jeOfficeService.doExecEvent(jeOfficeVo, "before");
            //处理页眉
            List<XWPFHeader> docHeaders = doc.getHeaderList();
            //处理页脚
            List<XWPFFooter> docFooters = doc.getFooterList();
            //段落
            List<XWPFParagraph> docPghs = doc.getParagraphs();
            //表格
            List<XWPFTable> docTables = doc.getTables();
            //其它表格(表格嵌入到表格内)
            List<XWPFTable> otherTables=new ArrayList<>();
            //图表
            List<XWPFChart> docCharts = doc.getCharts();
            //段落
            //一、替换单条数据源内容
            for (XWPFHeader docHeader : docHeaders) {
                List<XWPFParagraph> docHeaderPghs = docHeader.getParagraphs();
                for(XWPFParagraph docPgh:docHeaderPghs){
                    doDocParagraph(docPgh,jeOfficeVo,"one");
                }
            }
            for (XWPFFooter docFooter : docFooters) {
                List<XWPFParagraph> docFooterPghs = docFooter.getParagraphs();
                for(XWPFParagraph docPgh:docFooterPghs){
                    doDocParagraph(docPgh,jeOfficeVo,"one");
                }
            }
            for (int tableIndex=0;tableIndex<docTables.size();tableIndex++) {
                XWPFTable docTable = docTables.get(tableIndex);
                List<XWPFTableRow> rows = docTable.getRows();
                for (int row = 0; row < rows.size(); row++) {
                    XWPFTableRow tableRow = rows.get(row);
                    List<XWPFTableCell> cells = tableRow.getTableCells();
                    for (int col = 0; col < cells.size(); col++) {
                        XWPFTableCell cell=cells.get(col);
                        List<XWPFTable> cellTables=cell.getTables();
                        if(cellTables!=null && cellTables.size()>0){
                            otherTables.addAll(cellTables);
                        }
                    }
                }
            }
            for (int tableIndex=0;tableIndex<docTables.size();tableIndex++) {
                XWPFTable docTable = docTables.get(tableIndex);
                List<XWPFTableRow> rows=docTable.getRows();
                for (int row=0;row<rows.size();row++) {
                    XWPFTableRow tableRow=rows.get(row);
                    List<XWPFTableCell> cells=tableRow.getTableCells();
                    for (int col=0;col<cells.size();col++) {
                        XWPFTableCell cell=cells.get(col);
                        JeWordTableVo jeWordTableVo=new JeWordTableVo(docTable,rows,cells,tableRow,cell,tableIndex,row,col);
                        jeOfficeVo.setJeWordTableVo(jeWordTableVo);
                        List<XWPFParagraph> docTablePghs = cell.getParagraphs();
                        for(XWPFParagraph docPgh:docTablePghs){
                            doDocParagraph(docPgh,jeOfficeVo,"one");
                        }
                    }
                }
            }
            for (int tableIndex=0;tableIndex<otherTables.size();tableIndex++) {
                XWPFTable docTable = otherTables.get(tableIndex);
                List<XWPFTableRow> rows=docTable.getRows();
                for (int row=0;row<rows.size();row++) {
                    XWPFTableRow tableRow=rows.get(row);
                    List<XWPFTableCell> cells=tableRow.getTableCells();
                    for (int col=0;col<cells.size();col++) {
                        XWPFTableCell cell=cells.get(col);
                        JeWordTableVo jeWordTableVo=new JeWordTableVo(docTable,rows,cells,tableRow,cell,tableIndex,row,col);
                        jeOfficeVo.setJeWordTableVo(jeWordTableVo);
                        List<XWPFParagraph> docTablePghs = cell.getParagraphs();
                        for(XWPFParagraph docPgh:docTablePghs){
                            doDocParagraph(docPgh,jeOfficeVo,"one");
                        }
                    }
                }
            }
            for(XWPFParagraph docPgh:docPghs){
                doDocParagraph(docPgh,jeOfficeVo,"one");
            }
//            for(XWPFChart docChart:docCharts){
//                doDocChart(docChart,jeOfficeVo);
//            }
            //二、处理多条数据源内容
            for(XWPFParagraph docPgh:docPghs){
                doDocParagraph(docPgh,jeOfficeVo,"more");
            }
            for (int tableIndex=0;tableIndex<docTables.size();tableIndex++) {
                XWPFTable docTable=docTables.get(tableIndex);
                List<XWPFTableRow> rows=docTable.getRows();
                for (int row=0;row<rows.size();row++) {
                    XWPFTableRow tableRow=rows.get(row);
                    List<XWPFTableCell> cells=tableRow.getTableCells();
                    for (int col=0;col<cells.size();col++) {
                        String wordRowCol=tableIndex+"_"+(row)+"_"+col;
                        if(jeOfficeVo.getJeWordRows().contains(wordRowCol)){
                            continue;
                        }
                        XWPFTableCell cell=cells.get(col);
                        JeWordTableVo jeWordTableVo=new JeWordTableVo(docTable,rows,cells,tableRow,cell,tableIndex,row,col);
                        jeOfficeVo.setJeWordTableVo(jeWordTableVo);
                        List<XWPFParagraph> docTablePghs = cell.getParagraphs();
                        for(XWPFParagraph docPgh:docTablePghs){
                            doDocParagraph(docPgh,jeOfficeVo,"more");
                        }
                    }
                }
            }
            for (int tableIndex=0;tableIndex<otherTables.size();tableIndex++) {
                XWPFTable docTable=otherTables.get(tableIndex);
                List<XWPFTableRow> rows=docTable.getRows();
                for (int row=0;row<rows.size();row++) {
                    XWPFTableRow tableRow=rows.get(row);
                    List<XWPFTableCell> cells=tableRow.getTableCells();
                    for (int col=0;col<cells.size();col++) {
                        String wordRowCol=tableIndex+"_"+(row)+"_"+col;
                        if(jeOfficeVo.getJeWordRows().contains(wordRowCol)){
                            continue;
                        }
                        XWPFTableCell cell=cells.get(col);
                        JeWordTableVo jeWordTableVo=new JeWordTableVo(docTable,rows,cells,tableRow,cell,tableIndex,row,col);
                        jeOfficeVo.setJeWordTableVo(jeWordTableVo);
                        List<XWPFParagraph> docTablePghs = cell.getParagraphs();
                        for(XWPFParagraph docPgh:docTablePghs){
                            doDocParagraph(docPgh,jeOfficeVo,"more");
                        }
                    }
                }
            }
            //执行事件
            jeOfficeService.doExecEvent(jeOfficeVo, "after");
            doc.write(outputStream);
            doc.close();
            //输出转输入
            byte[] filebytes = outputStream.toByteArray();
            jeOfficeVo.setFileSize(new Long(filebytes.length));
            ByteArrayInputStream inputStream = IoUtil.toStream(filebytes);
            //关闭ExcelWriter outputStream
            IoUtil.close(outputStream);
            IoUtil.close(fileIo);
            jeOfficeVo.setInputStream(inputStream);
            jeOfficeVo.setFileSize(new Long(filebytes.length));
            //如果转pdf
            if(jeOfficeVo.getConvertPdf()){
                byte[] pdfbytes= AsposeUtils.wordToPdf(filebytes);
                if(pdfbytes!=null){
                    jeOfficeVo.setPreviewFileSize(new Long(pdfbytes.length));
                    jeOfficeVo.setPreviewSuffix("pdf");
                    jeOfficeVo.setPreviewContextType("application/pdf");
                    jeOfficeVo.setPreviewStream(IoUtil.toStream(pdfbytes));
                }
            }
            returnObj.put("success", true);
            returnObj.put("obj", "操作成功!");
        } catch (Exception e) {
            e.printStackTrace();
            returnObj.put("success", false);
            returnObj.put("obj", "系统导出出错了，请联系管理员!");
        }
    }
    public void doDocParagraph(XWPFParagraph docPgh, JeOfficeVo jeOfficeVo, String type){
        List<XWPFRun> runs = docPgh.getRuns();
        int runSize=runs.size();
        for(int runIndex=0;runIndex<runSize;runIndex++){
            XWPFRun run=runs.get(runIndex);
            String runText=run.getText(0);
            if(StringUtil.isEmpty(runText))continue;
            //
            if(runText.indexOf("{")!=-1 && runText.indexOf("}",runText.indexOf("{"))==-1 && jeOfficeVo.getJeWordTableVo()!=null && jeOfficeVo.getJeWordTableVo().getCell()!=null){
                for(int rI=runIndex+1;rI<runSize;rI++){
                    XWPFRun nextRun=runs.get(rI);
                    String nextText=nextRun.getText(0);
                    if(StringUtil.isNotEmpty(nextText)){
                        runText+=nextText;
                        nextRun.setText("",0);
                    }
                }
            }
            System.out.println(runText);
            int startIndex=0;
            boolean noData=false;
            boolean rowtext=false;
            DynaBean linkField=null;
            DynaBean linkBean=null;
            while(runText.indexOf("{",startIndex)!=-1 && runText.indexOf("}",runText.indexOf("{",startIndex))!=-1){
                String fieldStr=runText.substring(runText.indexOf("{")+1,runText.indexOf("}"));
                String dsCode="";
                String fieldCode="";
                if(fieldStr.split("\\.").length==2){
                    dsCode=fieldStr.split("\\.")[0];
                    fieldCode=fieldStr.split("\\.")[1];
                }else if(jeOfficeVo.getOfficeDatas().size()==1){
                    dsCode=jeOfficeVo.getOfficeDatas().get(0).getCode();
                    fieldCode=fieldStr;
                }
                OfficeDataVo officeDataVo=jeOfficeVo.getOfficeDataVo(dsCode);
                if(officeDataVo==null){
                    break;
                }
                System.out.println(dsCode+"-"+fieldCode);
                DynaBean fieldInfo=officeDataVo.getField(fieldCode);
                if("bean".equals(officeDataVo.getType())){
                    if("one".equals(type)){
                        DynaBean useBean=officeDataVo.getDynaBean();
                        String value=doDocRunValue(useBean,fieldInfo,docPgh,runIndex,run,jeOfficeVo);
                        runText=runText.replace("{"+fieldStr+"}",value);
                        startIndex=startIndex+(value.length()-("{"+fieldStr+"}").length());
                        if(startIndex<0){
                            startIndex=0;
                        }
                        if(StringUtil.isNotEmpty(value) && "rowtext".equals(fieldInfo.getStr("WORD_TYPE"))){
                            rowtext=true;
                            if("1".equals(fieldInfo.getStr("WORD_ROWIMG")) && StringUtil.isNotEmpty(fieldInfo.getStr("WORD_IMGFIELD"))){
                                linkField=fieldInfo;
                                linkBean=useBean;
                            }
                        }
                    }else{
                        startIndex=runText.indexOf("}",runText.indexOf("{",startIndex));
                    }
                }else if("table".equals(type)){
                    String value=doDocRunValue(jeOfficeVo.getJeWordTableVo().getUseBean(),fieldInfo,docPgh,runIndex,run,jeOfficeVo);
                    runText=runText.replace("{"+fieldStr+"}",value);
                    startIndex=startIndex+(value.length()-("{"+fieldStr+"}").length());
                    if(startIndex<0){
                        startIndex=0;
                    }
                    if(StringUtil.isNotEmpty(value) && "rowtext".equals(fieldInfo.getStr("WORD_TYPE"))){
                        if("1".equals(fieldInfo.getStr("WORD_ROWIMG")) && StringUtil.isNotEmpty(fieldInfo.getStr("WORD_IMGFIELD"))){
                            linkField=fieldInfo;
                            linkBean=jeOfficeVo.getJeWordTableVo().getUseBean();
                        }
                        rowtext=true;
                    }
                }else{
                    if("one".equals(type)){
                        startIndex=runText.indexOf("}",runText.indexOf("{",startIndex));
                    }else {
                        List<DynaBean> lists = officeDataVo.getLists();
                        DynaBean useBean = null;
                        if ("TABLE".equals(fieldInfo.getStr("WORD_ROWTYPE"))) {
                            JeWordTableVo jeWordTableVo=jeOfficeVo.getJeWordTableVo();
                            XWPFTable xwpfTable=jeWordTableVo.getTable();
                            XWPFTableRow nowRow=jeWordTableVo.getRow();
                            //是否自动增行
                            String rowData=fieldInfo.getStr("WORD_ROWDATA");
                            //同行增行字段
                            String rowFieldCode=fieldInfo.getStr("WORD_ROWFIELD");
//                            int addIndex=jeOfficeVo.getJeWordRows().get(jeWordTableVo.getTableIndex());
                            //开始增加行数
                            int rowIndex=jeWordTableVo.getRowIndex();
                            for(int dataIndex=0;dataIndex<lists.size();dataIndex++){
                                DynaBean bean=lists.get(dataIndex);
                                //如果是第二行并且设定自动增行且无关联行数据则直接加行
                                if(dataIndex>0 && "1".equals(rowData) && (StringUtil.isEmpty(rowFieldCode) || rowFieldCode.equals(fieldCode))){
                                    CTRow ctrow=null;
                                    try {
                                        ctrow = CTRow.Factory.parse(nowRow.getCtRow().newInputStream());
                                    } catch (Exception e) {
                                        e.printStackTrace();
                                    }
                                    XWPFTableRow newRow = new XWPFTableRow(ctrow, xwpfTable);
                                    List<XWPFTableCell> newCells=newRow.getTableCells();
                                    int newRowIndex=rowIndex+dataIndex;
                                    for(int col=0;col<newCells.size();col++){
                                        XWPFTableCell newCell=newCells.get(col);
                                        List<XWPFParagraph> newCellPghs = newCell.getParagraphs();
                                        for(XWPFParagraph newCellPgh:newCellPghs){
                                            jeOfficeVo.getJeWordTableVo().setUseBean(bean);
                                            doDocParagraph(newCellPgh,jeOfficeVo,"table");
                                        }
                                        String wordRowCol=jeWordTableVo.getTableIndex()+"_"+newRowIndex+"_"+col;
                                        jeOfficeVo.getJeWordRows().add(wordRowCol);
                                    }
                                    //在这里获取数据
                                    xwpfTable.addRow(newRow,rowIndex+dataIndex);//增行正确
                                }
                            }
//                            //表格前列合并
//                            if("1".equals(fieldInfo.getStr("WORD_BGQLHB")) && lists.size()>0){
//                                mergeCellsVertically(jeWordTableVo.getTable(),jeWordTableVo.getCellIndex()-1,jeWordTableVo.getRowIndex(),jeWordTableVo.getRowIndex()+lists.size());
//                            }
                            for(int dataIndex=0;dataIndex<lists.size();dataIndex++) {
                                DynaBean bean = lists.get(dataIndex);
                                if(dataIndex==0){
                                    List<XWPFTableCell> newCells=jeWordTableVo.getRow().getTableCells();
                                    int newRowIndex=rowIndex+dataIndex;
                                    for(int col=0;col<newCells.size();col++){
                                        XWPFTableCell newCell=newCells.get(col);
                                        List<XWPFParagraph> newCellPghs = newCell.getParagraphs();
                                        for(XWPFParagraph newCellPgh:newCellPghs){
                                            jeOfficeVo.getJeWordTableVo().setUseBean(bean);
                                            doDocParagraph(newCellPgh,jeOfficeVo,"table");
                                        }
                                        String wordRowCol=jeWordTableVo.getTableIndex()+"_"+newRowIndex+"_"+col;
                                        jeOfficeVo.getJeWordRows().add(wordRowCol);
                                    }
                                    break;
                                }
                            }
                            runText="";
                            noData=true;
                            if(lists.size()<=0){
                                noData=false;
                            }
                        } else {
                            //处理自动增行
                            if ("1".equals(fieldInfo.getStr("WORD_ROWDATA"))) {
                                int rowSize = -1;//为-1则代表去掉当前行
                                for (DynaBean bean : lists) {
                                    String rowFields = bean.getStr("_ROWFIELD_");
                                    if (StringUtil.isNotEmpty(rowFields) && ArrayUtils.contains(rowFields.split(","), fieldCode)) {
                                        continue;
                                    } else {
                                        if (StringUtil.isEmpty(rowFields)) {
                                            rowFields = fieldCode;
                                        } else {
                                            rowFields += ("," + fieldCode);
                                        }
                                        bean.set("_ROWFIELD_", rowFields);
                                        rowSize++;
                                    }
                                }
                                if (rowSize > 0) {
                                    run.addBreak();
                                }
                                for (int row = 0; row < rowSize; row++) {
                                    XWPFRun newRun = docPgh.insertNewRun(row + runIndex + 1);
                                    newRun.setText(runText);
                                    newRun.addBreak();
                                    int fontSize = run.getFontSize();
                                    String fontFamily = run.getFontFamily();
                                    //设置字体大小、格式
                                    if (StringUtil.isNotEmpty(fontFamily)) {
                                        newRun.setFontFamily(fontFamily);
                                    }
                                    if (fontSize >= 0) {
                                        newRun.setFontSize(fontSize);
                                    }
                                    runSize++;
                                }
                            }
                            for (DynaBean bean : lists) {
                                String useField = bean.getStr("_USEFIELD_", "");
                                if (StringUtil.isNotEmpty(useField) && ArrayUtils.contains(useField.split(","), fieldCode)) {
                                    continue;
                                } else {
                                    if (StringUtil.isEmpty(useField)) {
                                        useField = fieldCode;
                                    } else {
                                        useField += ("," + fieldCode);
                                    }
                                    bean.set("_USEFIELD_", useField);
                                    useBean = bean;
                                    break;
                                }
                            }
                            if (useBean != null) {
                                String value = doDocRunValue(useBean, fieldInfo, docPgh, runIndex, run, jeOfficeVo);
                                runText = runText.replace("{" + fieldStr + "}", value);
                                startIndex = startIndex + (value.length() - ("{" + fieldStr + "}").length());
                                if (startIndex < 0) {
                                    startIndex = 0;
                                }
                            } else {
                                startIndex = runText.indexOf("}", runText.indexOf("{", startIndex));
                            }
                        }
                    }
                }
            }
            if(!noData) {
                if(rowtext && StringUtil.isNotEmpty(runText)){
                    String[] lines = runText.split("\n");
                    if(lines.length > 0) {
                        if(linkField!=null){
                            JSONArray linkVals=getLinkFiles(linkBean,linkField.getStr("WORD_IMGFIELD"),linkField.getStr("FIELD_CODE"));
                            doImgText(lines[0],linkVals,run,true);
                            for (int i = 1; i < lines.length; i++) {
                                // add break and insert new text
                                run.addBreak();
                                doImgText(lines[i],linkVals,run,false);
                            }
                        }else {
                            run.setText(lines[0], 0);
                            for (int i = 1; i < lines.length; i++) {
                                // add break and insert new text
                                run.addBreak();
                                run.setText(lines[i]);
                            }
                        }
                    }
                }else {
                    run.setText(runText, 0);
                }
            }
        }
    }
    public void doDocChart(DynaBean dynaBean, DynaBean fieldInfo, XWPFParagraph docPgh, int runIndex, XWPFRun run, JeOfficeVo jeOfficeVo) {
        XWPFDocument doc = jeOfficeVo.getJeWordVo().getDoc();
        JSONObject chartCfg = new JSONObject();
        if (StringUtil.isNotEmpty(fieldInfo.getStr("WORD_CHARTCFG"))) {
            JSONArray cfgArrays = JSONArray.parseArray(fieldInfo.getStr("WORD_CHARTCFG"));
            for (int i = 0; i < cfgArrays.size(); i++) {
                JSONObject cfgObj = cfgArrays.getJSONObject(i);
                String code = cfgObj.getString("code");
                String val = cfgObj.getString("value");
                chartCfg.put(code, val);
            }
        }
        //获取数据源
        OfficeDataVo dataVo = jeOfficeVo.getOfficeDataVo(chartCfg.getString("dsCode"));
        List<DynaBean> datas = dataVo.getLists();
        int width = 10;
        int height = 10;
        if (StringUtil.isNotEmpty(chartCfg.getString("width"))) {
            width = Integer.parseInt(chartCfg.getString("width"));
        }
        if (StringUtil.isNotEmpty(chartCfg.getString("height"))) {
            height = Integer.parseInt(chartCfg.getString("height"));
        }
        // 2、创建chart图表对象,抛出异常
        XWPFChart chart = null;

        try {
            //15 * Units.EMU_PER_CENTIMETER, 10 * Units.EMU_PER_CENTIMETER
            chart = doc.createChart(run, width * Units.EMU_PER_CENTIMETER, height * Units.EMU_PER_CENTIMETER);
        } catch (InvalidFormatException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        // 3、图表相关设置
        if (StringUtil.isNotEmpty(chartCfg.getString("title"))) {
            chart.setTitleText(chartCfg.getString("title")); // 图表标题
        } else {
            chart.setTitleText(""); // 图表标题
        }
        // 图例是否覆盖标题
        if ("1".equals(chartCfg.getString("titleOverlay"))) {
            chart.setTitleOverlay(true);
        } else {
            chart.setTitleOverlay(false);
        }
        // 4、图例设置
        if ("1".equals(chartCfg.getString("legend"))){
            XDDFChartLegend legend = chart.getOrAddLegend();
            //legend.setOverlay(true);
            // 图例位置:上下左右
            if("top".equals(chartCfg.getString("legendPos"))) {
                legend.setPosition(LegendPosition.TOP);
            }else if("left".equals(chartCfg.getString("legendPos"))){
                legend.setPosition(LegendPosition.LEFT);
            }else if("right".equals(chartCfg.getString("legendPos"))){
                legend.setPosition(LegendPosition.RIGHT);
            }else if("bottom".equals(chartCfg.getString("legendPos"))){
                legend.setPosition(LegendPosition.BOTTOM);
            }else if("topright".equals(chartCfg.getString("legendPos"))){
                legend.setPosition(LegendPosition.TOP_RIGHT);
            }
        }
        //准备数据
        String xField=chartCfg.getString("xField");
        String yField=chartCfg.getString("yField");
        XDDFCategoryAxis xAxis=null;
        //X轴(分类轴)相关设置
        if("top".equals(chartCfg.getString("xPos"))) {
            xAxis=chart.createCategoryAxis(AxisPosition.TOP);
        }else if("left".equals(chartCfg.getString("xPos"))){
            xAxis=chart.createCategoryAxis(AxisPosition.LEFT);
        }else if("right".equals(chartCfg.getString("xPos"))){
            xAxis=chart.createCategoryAxis(AxisPosition.RIGHT);
        }else if("bottom".equals(chartCfg.getString("xPos"))){
            xAxis=chart.createCategoryAxis(AxisPosition.BOTTOM);
        }
        if(StringUtil.isNotEmpty(chartCfg.getString("xTitle"))){
            xAxis.setTitle(chartCfg.getString("xTitle"));
        }
        String[] xAxisData=ArrayUtils.getBeanFieldArray(datas,xField);
        XDDFCategoryDataSource xAxisSource = XDDFDataSourcesFactory.fromArray(xAxisData); // 设置X轴数据
        // 6、Y轴(值轴)相关设置
        XDDFValueAxis yAxis=null;
        if("top".equals(chartCfg.getString("yPos"))) {
            yAxis=chart.createValueAxis(AxisPosition.TOP);
        }else if("left".equals(chartCfg.getString("yPos"))){
            yAxis=chart.createValueAxis(AxisPosition.LEFT);
        }else if("right".equals(chartCfg.getString("yPos"))){
            yAxis=chart.createValueAxis(AxisPosition.RIGHT);
        }else if("bottom".equals(chartCfg.getString("yPos"))){
            yAxis=chart.createValueAxis(AxisPosition.BOTTOM);
        }
        if(StringUtil.isNotEmpty(chartCfg.getString("yTitle"))){
            yAxis.setTitle(chartCfg.getString("yTitle"));
        }
        String[] yAxisDataStr=new String[0];
        XDDFCategoryDataSource yAxisSourceStr=null;
        Integer[] yAxisDataInt=new Integer[0];
        XDDFNumericalDataSource<Integer> yAxisSourceInt=null;
        Double[] yAxisDataDouble=new Double[0];
        XDDFNumericalDataSource<Double> yAxisSourceDouble=null;
        if("string".equals(chartCfg.getString("yFieldType"))) {
            yAxisDataStr=ArrayUtils.getBeanFieldArray(datas, yField);
            yAxisSourceStr=XDDFDataSourcesFactory.fromArray(yAxisDataStr);
        }else if("int".equals(chartCfg.getString("yFieldType"))){
            Integer[] vals=new Integer[datas.size()];
            for(int i=0;i<datas.size();i++){
                vals[i]=datas.get(i).getInt(yField,0);
            }
            yAxisDataInt=vals;
            yAxisSourceInt=XDDFDataSourcesFactory.fromArray(yAxisDataInt);
        }else if("double".equals(chartCfg.getString("yFieldType"))){
            Double[] vals=new Double[datas.size()];
            for(int i=0;i<datas.size();i++){
                vals[i]=datas.get(i).getDouble(yField,0);
            }
            yAxisDataDouble=vals;
            yAxisSourceDouble=XDDFDataSourcesFactory.fromArray(yAxisDataDouble);
        }
        //柱状图
        if("bar".equals(fieldInfo.getStr("WORD_CHART"))){
            XDDFBarChartData barChart = (XDDFBarChartData) chart.createData(ChartTypes.BAR, xAxis, yAxis);
            XDDFBarChartData.Series barSeries=null;
            if("int".equals(chartCfg.getString("yFieldType"))){
                barSeries=(XDDFBarChartData.Series) barChart.addSeries(xAxisSource, yAxisSourceInt);
            }else if("double".equals(chartCfg.getString("yFieldType"))){
                barSeries=(XDDFBarChartData.Series) barChart.addSeries(xAxisSource, yAxisSourceDouble);
            }
            if(StringUtil.isNotEmpty(chartCfg.getString("legendTitle"))) {
                barSeries.setTitle(chartCfg.getString("legendTitle"), null); // 图例标题
            }
            barSeries.setShowLeaderLines(true);
            chart.plot(barChart);
            //折线图
        }else if("line".equals(fieldInfo.getStr("WORD_CHART"))){
            // 7、创建折线图对象
            XDDFLineChartData lineChart = (XDDFLineChartData) chart.createData(ChartTypes.LINE, xAxis, yAxis);
            XDDFLineChartData.Series lineSeries = null;
            if("int".equals(chartCfg.getString("yFieldType"))){
                lineSeries=(XDDFLineChartData.Series) lineChart.addSeries(xAxisSource, yAxisSourceInt);
            }else if("double".equals(chartCfg.getString("yFieldType"))){
                lineSeries=(XDDFLineChartData.Series) lineChart.addSeries(xAxisSource, yAxisSourceDouble);
            }
            if(StringUtil.isNotEmpty(chartCfg.getString("legendTitle"))) {
                lineSeries.setTitle(chartCfg.getString("legendTitle"), null); // 图例标题
            }
            lineSeries.setSmooth(true); // 线条样式:true平滑曲线,false折线
            lineSeries.setMarkerSize((short) 6); // 标记点大小
            lineSeries.setMarkerStyle(MarkerStyle.CIRCLE); // 标记点样式
            chart.plot(lineChart);
            //雷达图
        }else if("radar".equals(fieldInfo.getStr("WORD_CHART"))){
            XDDFRadarChartData radarChart = (XDDFRadarChartData) chart.createData(ChartTypes.RADAR, xAxis, yAxis);
            XDDFRadarChartData.Series radarSeries=null;
            if("int".equals(chartCfg.getString("yFieldType"))){
                radarSeries=(XDDFRadarChartData.Series) radarChart.addSeries(xAxisSource, yAxisSourceInt);
            }else if("double".equals(chartCfg.getString("yFieldType"))){
                yAxisSourceDouble.setFormatCode("#%");
                radarSeries=(XDDFRadarChartData.Series) radarChart.addSeries(xAxisSource, yAxisSourceDouble);
            }
            if(StringUtil.isNotEmpty(chartCfg.getString("legendTitle"))) {
                radarSeries.setTitle(chartCfg.getString("legendTitle"), null); // 图例标题
            }else{
                radarSeries.setTitle("",null);
            }
            radarSeries.setShowLeaderLines(true);
            //隐藏数据标签
            CTRadarChart ctRadarChart =chart.getCTChart().getPlotArea().getRadarChartArray(0);
            CTRadarSer ctRadarSer=ctRadarChart.getSerArray(0);
            CTDLbls newDLbls = ctRadarSer.getDLbls();//数据标签
//            newDLbls.addNewShowCatName().setVal(false);
//            newDLbls.addNewShowLeaderLines().setVal(false);
//            newDLbls.addNewShowLegendKey().setVal(false);
//            newDLbls.addNewShowPercent().setVal(false);
//            newDLbls.addNewShowBubbleSize().setVal(false);
//            newDLbls.addNewShowVal().setVal(false);//数据标签 显示值
            newDLbls.addNewDelete().setVal(true);
//            newDLbls.addShowSerName().setVal(false);//数据标签 显示类别名称
//            newDLbls.getShowPercent().setVal(false);
//            newDLbls.getShowBubbleSize().setVal(false);
//            newDLbls.getShowLeaderLines().setVal(false);
//            newDLbls.getShowLegendKey().setVal(false);//图例化标签
            CTValAx catAy = chart.getCTChart().getPlotArea().getValAxArray(0);
            CTLineProperties ctLine = catAy.addNewMajorGridlines().addNewSpPr().addNewLn();
            ctLine.addNewPrstDash().setVal(STPresetLineDashVal.SOLID);
            chart.plot(radarChart);
            //饼图
        }else if("pie".equals(fieldInfo.getStr("WORD_CHART"))){
            XDDFPieChartData pieChart = (XDDFPieChartData) chart.createData(ChartTypes.PIE, xAxis, yAxis);
            XDDFPieChartData.Series pieSeries=null;
            if("int".equals(chartCfg.getString("yFieldType"))){
                pieSeries=(XDDFPieChartData.Series) pieChart.addSeries(xAxisSource, yAxisSourceInt);
            }else if("double".equals(chartCfg.getString("yFieldType"))){
                pieSeries=(XDDFPieChartData.Series) pieChart.addSeries(xAxisSource, yAxisSourceDouble);
            }
            if(StringUtil.isNotEmpty(chartCfg.getString("legendTitle"))) {
                pieSeries.setTitle(chartCfg.getString("legendTitle"), null); // 图例标题
            }
            pieSeries.setShowLeaderLines(true);
            chart.plot(pieChart);
        }
    }
    public String getDocFieldValue(DynaBean dynaBean, DynaBean fieldInfo, JeOfficeVo jeOfficeVo){
        String fieldCode=fieldInfo.getStr("FIELD_CODE");
        String fieldType=fieldInfo.getStr("FIELD_TYPE");
        String wordType=fieldInfo.getStr("WORD_TYPE");
        String prefix=fieldInfo.getStr("WORD_PREFIX","");
        String suffix=fieldInfo.getStr("WORD_SUFFIX","");
        String br=fieldInfo.getStr("WORD_BR");
        String configInfo=fieldInfo.getStr("FIELD_CONFIGINFO");
        String otherConfig=fieldInfo.getStr("FIELD_OTHERCONFIG");
        String value=dynaBean.getStr(fieldCode,"");
        if("DATE".equals(fieldType)){
            if(StringUtil.isNotEmpty(fieldInfo.getStr("FIELD_CONFIGINFO")) && StringUtil.isNotEmpty(value)){
                Date d= DateUtils.getDate(value,DateUtils.DAFAULT_DATE_FORMAT);
                if(d!=null) {
                    value = DateUtils.formatDate(d, fieldInfo.getStr("FIELD_CONFIGINFO"));
                }
            }
        }else if("DATETIME".equals(fieldType)){
            if(StringUtil.isNotEmpty(fieldInfo.getStr("FIELD_CONFIGINFO")) && StringUtil.isNotEmpty(value)){
                Date d=DateUtils.getDate(value,DateUtils.DAFAULT_DATETIME_FORMAT);
                if(d!=null) {
                    value = DateUtils.formatDate(d, fieldInfo.getStr("FIELD_CONFIGINFO"));
                }
            }
        }else if("MOREFIELD".equals(fieldType)){
            Set<Map.Entry<String,String>> ddSet=new HashSet<>();
            ddSet.addAll(OfficeUtil.getDynaMap(dynaBean).entrySet());
            value= StringUtil.parseKeyWord(configInfo,ddSet);
        }else if("WFDATA".equals(fieldType)){
            value = dynaBean.getStr("WF_" + configInfo, "");
            if(configInfo.endsWith("_date")){
                if(StringUtil.isNotEmpty(otherConfig) && StringUtil.isNotEmpty(value)){
                    Date d=DateUtils.getDate(value,DateUtils.DAFAULT_DATE_FORMAT);
                    value=DateUtils.formatDate(d,otherConfig);
                }
            }else if(configInfo.endsWith("_time")){
                if(StringUtil.isNotEmpty(otherConfig) && StringUtil.isNotEmpty(value)){
                    Date d=DateUtils.getDate(value,DateUtils.DAFAULT_DATETIME_FORMAT);
                    value=DateUtils.formatDate(d,otherConfig);
                }
            }
        }else if("LISTDIC".equals(fieldType) || "LISTQUERY".equals(fieldType)){
            if("text".equals(wordType) || "rowtext".equals(wordType)){
                String dzCode="";
                if(StringUtil.isNotEmpty(configInfo)) {
                    dzCode=configInfo.split(",")[0];
                }
                List<DynaBean> dicLists=jeOfficeVo.getDzValues().get(dzCode);
                List<String> names=new ArrayList<>();
                List<String> values=new ArrayList<>();
                String displayField=fieldInfo.getStr("WORD_CBBFIELD");
                String checkBox=fieldInfo.getStr("WORD_CHECKBOX");
                String isBreak=fieldInfo.getStr("WORD_BREAK");
                String cbbtext=fieldInfo.getStr("WORD_CBBTEXT");
                if("LISTDIC".equals(fieldType) && StringUtil.isEmpty(displayField)){
                    displayField="text";
                }else if("LISTQUERY".equals(fieldType) && StringUtil.isEmpty(displayField)){
                    displayField=fieldCode;
                }
                for(DynaBean dicInfo:dicLists){
                    String dicVal=dicInfo.getStr(displayField,"");
                    if(StringUtil.isNotEmpty(dicVal)) {
                        names.add(dicVal);
                    }
                    if("LISTDIC".equals(fieldType) && StringUtil.isNotEmpty(fieldInfo.getStr("FIELD_DZCONFIG"))){
                        String[] dzConfigs=fieldInfo.getStr("FIELD_DZCONFIG").split(",");
                        int flagCs=0;
                        for(String dzConfig:dzConfigs){
                            if(StringUtil.isEmpty(dzConfig)){
                                flagCs++;
                                continue;
                            }
                            String thisField=dzConfig.split("~")[0];
                            String targerField=dzConfig.split("~")[1];
                            if(ArrayUtils.contains(dynaBean.getStr(thisField,"").split(","),dicInfo.getStr(targerField))){
                                flagCs++;
                            }
                        }
                        if(flagCs==dzConfigs.length){
                            value=dicVal;
                            values.add(dicVal);
                        }
                    }
                }
                value=StringUtil.buildSplitString(ArrayUtils.getArray(values),",");
                if(StringUtil.isEmpty(value) && StringUtil.isNotEmpty(dynaBean.getStr(fieldCode,""))){
                    value=dynaBean.getStr(fieldCode,"");
                }
            }
        }
        if(StringUtil.isEmpty(value) && StringUtil.isNotEmpty(fieldInfo.getStr("FIELD_VALUE"))){
            value=fieldInfo.getStr("FIELD_VALUE","");
        }
        if("1".equals(br) && StringUtil.isNotEmpty(value)){
            value=value.replaceAll("&nbsp;"," ");
        }
//        if("rowtext".equals(wordType)){
//            value=value.replaceAll("\\n","");
//        }
        return value;
    }
    public String doDocRunValue(DynaBean dynaBean, DynaBean fieldInfo, XWPFParagraph docPgh, int runIndex, XWPFRun run, JeOfficeVo jeOfficeVo){
        String fieldCode=fieldInfo.getStr("FIELD_CODE");
        String fieldType=fieldInfo.getStr("FIELD_TYPE");
        String wordType=fieldInfo.getStr("WORD_TYPE");
        String prefix=fieldInfo.getStr("WORD_PREFIX","");
        String suffix=fieldInfo.getStr("WORD_SUFFIX","");
        String configInfo=fieldInfo.getStr("FIELD_CONFIGINFO");
        String otherConfig=fieldInfo.getStr("FIELD_OTHERCONFIG");
        String value="";
        if(StringUtil.isNotEmpty(fieldInfo.getStr("FIELD_VALCONFIG"))){
            String valConfig=fieldInfo.getStr("FIELD_VALCONFIG");
            String dsCode=fieldInfo.getStr("_DSCODE_");
            int startIndex=0;
            while(valConfig.indexOf("{",startIndex)!=-1 && valConfig.indexOf("}",valConfig.indexOf("{",startIndex))!=-1) {
                String fCode=valConfig.substring(valConfig.indexOf("{") + 1, valConfig.indexOf("}"));
                DynaBean fInfo=jeOfficeVo.getOfficeDataVo(dsCode).getField(fCode);
                if(fInfo==null){
                    startIndex = valConfig.indexOf("}", valConfig.indexOf("{", startIndex));
                }else {
                    String val = getDocFieldValue(dynaBean, fInfo, jeOfficeVo);
                    valConfig=valConfig.replace("{"+fCode+"}",val);
                    startIndex=startIndex+(value.length()-("{"+fCode+"}").length());
                    if(startIndex<0){
                        startIndex=0;
                    }
                }
            }
            value=valConfig;
        }else {
            value=getDocFieldValue(dynaBean, fieldInfo, jeOfficeVo);
        }
        if("WFDATA".equals(fieldType)) {
            if (configInfo.endsWith("_seal") || configInfo.lastIndexOf("_seal")!=-1) {
                if (StringUtil.isNotEmpty(value)) {
                    String fileKey = value.split("\\*")[1];
                    File file = documentInternalRpcService.readFile(fileKey);
                    InternalFileBO fileBO=documentInternalRpcService.selectFileByKey(fileKey);
                    int width = 50;
                    int height = 50;
                    if (StringUtil.isNotEmpty(otherConfig)) {
                        width = Integer.parseInt(otherConfig.split("\\*")[0]);
                        height = Integer.parseInt(otherConfig.split("\\*")[1]);
                    }
                    if (file.exists()) {
                        FileInputStream fileIo=null;
                        try {
                            fileIo=new FileInputStream(file);
                            run.addPicture(fileIo, XWPFDocument.PICTURE_TYPE_PNG, fileBO.getRelName(), Units.toEMU(width), Units.toEMU(height));
                        } catch (InvalidFormatException e) {
                            e.printStackTrace();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }finally {
                            IoUtil.close(fileIo);
                        }
                    }
                    value = prefix + "" + suffix;
                }
            }
        }
        if("cbb".equals(wordType)){
            String dzCode="";
            if(StringUtil.isNotEmpty(configInfo)) {
                dzCode=configInfo.split(",")[0];
            }
            List<DynaBean> dicLists=jeOfficeVo.getDzValues().get(dzCode);
            List<String> names=new ArrayList<>();
            List<String> values=new ArrayList<>();
            String displayField=fieldInfo.getStr("WORD_CBBFIELD");
            String checkBox=fieldInfo.getStr("WORD_CHECKBOX");
            String isBreak=fieldInfo.getStr("WORD_BREAK");
            String cbbtext=fieldInfo.getStr("WORD_CBBTEXT");
            if("LISTDIC".equals(fieldType) && StringUtil.isEmpty(displayField)){
                displayField="text";
            }else if("LISTQUERY".equals(fieldType) && StringUtil.isEmpty(displayField)){
                displayField=fieldCode;
            }
            for(DynaBean dicInfo:dicLists){
                String dicVal=dicInfo.getStr(displayField,"");
                if(StringUtil.isNotEmpty(dicVal)) {
                    names.add(dicVal);
                }
                if("LISTDIC".equals(fieldType) && StringUtil.isNotEmpty(fieldInfo.getStr("FIELD_DZCONFIG"))){
                    String[] dzConfigs=fieldInfo.getStr("FIELD_DZCONFIG").split(",");
                    int flagCs=0;
                    for(String dzConfig:dzConfigs){
                        if(StringUtil.isEmpty(dzConfig)){
                            flagCs++;
                            continue;
                        }
                        String thisField=dzConfig.split("~")[0];
                        String targerField=dzConfig.split("~")[1];
                        if(ArrayUtils.contains(dynaBean.getStr(thisField,"").split(","),dicInfo.getStr(targerField))){
                            flagCs++;
                        }
                    }
                    if(flagCs==dzConfigs.length){
                        value=dicVal;
                        values.add(dicVal);
                    }
                }
            }
            //TODO 设置下拉框并设置实际值
            List<CTSym> ctSymList=run.getCTR().getSymList();
            //自定义对勾样式
            if(StringUtil.isNotEmpty(cbbtext)){
                String cbbPrefix=cbbtext.split("##")[0];
                String cbbSuffix=cbbtext.split("##")[1];
                for(int i=0;i<names.size();i++){
                    String name=names.get(i);
                    run.setText(cbbPrefix);
                    if(values.contains(name)){
                        //对勾的方式
                        run.setText("√");
                    }else {
                        run.setText("  ");
                    }
                    run.setText(cbbSuffix+name);
                }
            }else{
                //多选框样式
                for(int i=0;i<names.size();i++){
                    String name=names.get(i);
//                    String charStr ="00A3";
//                    String wingType ="Wingdings 2";
//                    if(values.contains(name)){
//                        charStr ="0052";
//                        wingType ="Wingdings 2";
//                    }
                    String charStr ="00A8";
                    String wingType ="Wingdings";
                    if(values.contains(name)){
                        charStr ="00FE";
                        wingType ="Wingdings";
                    }
                    CTSym ctSym=getCTSym(wingType,charStr);
                    ctSymList.add(ctSym);
                    run.setText(name);
                    if("1".equals(isBreak) && i!=(names.size()-1)){
                        run.addBreak();
                    }
                }
            }
            return prefix+""+suffix;
            //图片
        }else if("cbbgrid".equals(wordType)){
            String dzCode="";
            if(StringUtil.isNotEmpty(configInfo)) {
                dzCode=configInfo.split(",")[0];
            }
            List<DynaBean> dicLists=jeOfficeVo.getDzValues().get(dzCode);
            List<String> names=new ArrayList<>();
            List<String> values=new ArrayList<>();
            String displayField=fieldInfo.getStr("WORD_CBBFIELD");
            String checkBox=fieldInfo.getStr("WORD_CHECKBOX");
            String isBreak=fieldInfo.getStr("WORD_BREAK");
            String cbbtext=fieldInfo.getStr("WORD_CBBTEXT");
            if("LISTDIC".equals(fieldType) && StringUtil.isEmpty(displayField)){
                displayField="text";
            }else if("LISTQUERY".equals(fieldType) && StringUtil.isEmpty(displayField)){
                displayField=fieldCode;
            }
            for(DynaBean dicInfo:dicLists){
                String dicVal=dicInfo.getStr(displayField,"");
                if(StringUtil.isNotEmpty(dicVal)) {
                    names.add(dicVal);
                }
                if("LISTDIC".equals(fieldType) && StringUtil.isNotEmpty(fieldInfo.getStr("FIELD_DZCONFIG"))){
                    String[] dzConfigs=fieldInfo.getStr("FIELD_DZCONFIG").split(",");
                    int flagCs=0;
                    for(String dzConfig:dzConfigs){
                        if(StringUtil.isEmpty(dzConfig)){
                            flagCs++;
                            continue;
                        }
                        String thisField=dzConfig.split("~")[0];
                        String targerField=dzConfig.split("~")[1];
                        if(ArrayUtils.contains(dynaBean.getStr(thisField,"").split(","),dicInfo.getStr(targerField))){
                            flagCs++;
                        }
                    }
                    if(flagCs==dzConfigs.length){
                        value=dicVal;
                        values.add(dicVal);
                    }
                }
            }
            JeWordTableVo jeWordTableVo=jeOfficeVo.getJeWordTableVo();
            //获取下一个行信息
            List<XWPFTableCell> cells=jeWordTableVo.getCells();
            XWPFTableRow nextRow=jeWordTableVo.getRows().get(jeWordTableVo.getRowIndex()+1);
            List<XWPFTableCell> nextCells=nextRow.getTableCells();
            int startIndex=jeWordTableVo.getCellIndex();
            String firstVal="";
            for(int i=0;i<names.size();i++) {
                XWPFTableCell nowCell=cells.get(i+startIndex);
                XWPFTableCell nextCell=nextCells.get(i+startIndex);
                String name = names.get(i);
                if(i==0){
                    firstVal=name;
                }else {
                    setTableCellValue(nowCell, name);
                }
//                nowCell.setText(name);
                if(values.contains(name)){
                    setTableCellValue(nextCell,"√");
//                    nextCell.setText("√");
                }
            }
            return prefix+firstVal+suffix;
        }else if("img".equals(wordType)){
            String fileKey="";
            if(StringUtil.isNotEmpty(value)){
                if(value.startsWith("[")){
                    JSONArray fileArray=JSONArray.parseArray(value);
                    if(fileArray.size()>0){
                        fileKey=fileArray.getJSONObject(0).getString("path");
                    }
                }else{
                    fileKey=value.split("\\*")[1];
                }
            }
            if(StringUtil.isNotEmpty(fileKey)) {
                File file = documentInternalRpcService.readFile(fileKey);
                InternalFileBO fileBO=documentInternalRpcService.selectFileByKey(fileKey);
                if (file.exists()) {
                    //TODO 图片待处理
                    int width = 50;
                    int height = 50;
                    if (StringUtil.isNotEmpty(otherConfig)) {
                        width = Integer.parseInt(otherConfig.split("\\*")[0]);
                        height = Integer.parseInt(otherConfig.split("\\*")[1]);
                    }
                    if (file.exists()) {
                        FileInputStream fis=null;
                        try {
                            fis=new FileInputStream(file);
                            run.addPicture(fis, XWPFDocument.PICTURE_TYPE_PNG, fileBO.getRelName(), Units.toEMU(width), Units.toEMU(height));
                        } catch (InvalidFormatException e) {
                            e.printStackTrace();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }finally {
                            IoUtil.close(fis);
                        }
                    }
                }
            }
            return prefix+""+suffix;
            //常规字段
        }else if("chart".equals(wordType)){
            doDocChart(dynaBean,fieldInfo,docPgh,0,run,jeOfficeVo);
            return "";
        }else {
            return prefix+value+suffix;
        }
    }
    private JSONArray getLinkFiles(DynaBean dynaBean, String linkFieldCode, String fieldCode){
        String linkValStr=dynaBean.getStr(linkFieldCode,"[]");
        JSONArray linkVals=JSONArray.parseArray(linkValStr);
        JSONArray reulsts=new JSONArray();
        for(int i=0;i<linkVals.size();i++){
            JSONObject linkVal=linkVals.getJSONObject(i);
            if(fieldCode.equals(linkVal.getString("fieldCode"))){
                reulsts.add(linkVal);
            }
        }
        return reulsts;
    }
    private void doImgText(String textVal, JSONArray linkVals, XWPFRun run, Boolean onePos){
//        if(StringUtil.isEmpty(textVal))return;
        Boolean haveFile=false;
        for(int i=0;i<linkVals.size();i++){
            JSONObject linkVal=linkVals.getJSONObject(i);
            String code=linkVal.getString("code");
            if(textVal.indexOf("{"+code+"}")!=-1){
                haveFile=true;
                textVal=textVal.replace("{"+code+"}","#,#");
                String[] textVals=textVal.split("#,#");
                String preVal="";
                if(textVals.length>0) {
                    preVal = textVals[0];
                }
                String sufVal="";
                if(textVals.length>1){
                    sufVal=textVals[1];
                }
                if(onePos){
                    run.setText(preVal,0);
                }else{
                    run.setText(preVal);
                }
                //加入图片
                String fileKey=linkVal.getString("id");
                if(StringUtil.isNotEmpty(fileKey)) {
                    File file = documentInternalRpcService.readFile(fileKey);
                    InternalFileBO fileBO=documentInternalRpcService.selectFileByKey(fileKey);
                    if (file!=null && file.exists()) {
                        //TODO 图片待处理
                        double width = Double.parseDouble(linkVal.getString("width"));
                        double height = Double.parseDouble(linkVal.getString("height"));
                        FileInputStream fis=null;
                        try {
                            fis=new FileInputStream(file);
                            XWPFPicture picture=run.addPicture(fis, XWPFDocument.PICTURE_TYPE_PNG, fileBO.getRelName(), Units.toEMU(width), Units.toEMU(height));
                        } catch (InvalidFormatException e) {
                            e.printStackTrace();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }finally {
                            IoUtil.close(fis);
                        }
                    }
                }
//                run.getParagraph().setAlignment(ParagraphAlignment.CENTER);
                run.setText(sufVal);
                break;
            }
        }
        if(!haveFile){
            if(onePos){
                run.setText(textVal,0);
            }else{
                run.setText(textVal);
            }
        }
    }
    /***
     *功能描述
     *添加特殊字符的xml
     * @author wenzhe.zhou
     * @date 2020/5/20
     * @param wingType
     * @param charStr
     * @return org.openxmlformats.schemas.wordprocessingml.x2006.main.CTSym
     */
    public CTSym getCTSym(String wingType, String charStr){
        CTSym sym = null;
        try {
            sym = CTSym.Factory
                    .parse("<xml-fragment w:font=\""
                            + wingType
                            + "\" w:char=\""
                            + charStr
                            + "\" xmlns:w=\"http://schemas.openxmlformats.org/wordprocessingml/2006/main\" xmlns:wne=\"http://schemas.microsoft.com/office/word/2006/wordml\"> </xml-fragment>");
        } catch (XmlException e) {
            e.printStackTrace();
        }
        return sym;
    }
    public void setTableCellValue(XWPFTableCell cell,String value){
        List<XWPFParagraph> docTablePghs = cell.getParagraphs();
        for(XWPFParagraph docPgh:docTablePghs){
            List<XWPFRun> runs = docPgh.getRuns();
            for(XWPFRun run:runs){
                run.setText(value,0);
            }
        }
    }
    /**
     * word单元格列合并
     * @param table 表格
     * @param row 合并列所在行
     * @param startCell 开始列
     * @param endCell 结束列
     * @date 2020年4月8日 下午4:43:54
     */
    public static void mergeCellsHorizontal(XWPFTable table, int row, int startCell, int endCell) {
        for (int i = startCell; i <= endCell; i++) {
            XWPFTableCell cell = table.getRow(row).getCell(i);
            if (i == startCell) {
                // The first merged cell is set with RESTART merge value
                cell.getCTTc().addNewTcPr().addNewHMerge().setVal(STMerge.RESTART);
            } else {
                // Cells which join (merge) the first one, are set with CONTINUE
                cell.getCTTc().addNewTcPr().addNewHMerge().setVal(STMerge.CONTINUE);
            }
        }
    }

    /**
     * word单元格行合并
     * @param table 表格
     * @param col 合并行所在列
     * @date 2020年4月8日 下午4:46:18
     */
    public static void mergeCellsVertically(XWPFTable table, int col,int fromRow, int toRow) {
        for(int rowIndex = fromRow; rowIndex <= toRow; rowIndex++){
            CTVMerge vmerge = CTVMerge.Factory.newInstance();
            if(rowIndex == fromRow){
                vmerge.setVal(STMerge.RESTART);
            } else {
                vmerge.setVal(STMerge.CONTINUE);
            }
            XWPFTableCell cell = table.getRow(rowIndex).getCell(col);
            CTTcPr tcPr = cell.getCTTc().getTcPr();

            if (tcPr != null) {
                tcPr.setVMerge(vmerge);
                //cell.getCTTc().setTcPr(tcPr);
            } else {
                tcPr = CTTcPr.Factory.newInstance();
                tcPr.setVMerge(vmerge);
                cell.getCTTc().setTcPr(tcPr);
            }
        }
    }
    @Override
    public void doTestPdf(HashMap<String, String> param, JSONObject returnObj) {
//        String fileKey=param.get("filekey");
//        FileBO fileBO=documentBusService.readFile(fileKey);
//        EndUser currentUser= SecurityUserHolder.getCurrentUser();
//        byte[] pdfByts=AsposeWordUtils.byteToPdf(IoUtil.readBytes(fileBO.getFile()));
//        InputStream pdfIo=IoUtil.toStream(pdfByts);
//        String fileName=fileBO.getRelName().substring(0,fileBO.getRelName().lastIndexOf(".")-1)+".pdf";
//        FileUpload uploadFile=new FileUpload(fileName,"application/pdf",new Long(pdfByts.length),pdfIo);
//        FileBO pdfBO=documentBusService.saveSingleFile(uploadFile,currentUser.getUserId());
//        String fileStr=pdfBO.getRelName()+"*"+pdfBO.getFileKey();
//        returnObj.put("success",true);
//        returnObj.put("obj",fileStr);
    }
}
